import { memo, useCallback, useEffect, useRef, useState } from 'react';
import { Position, useReactFlow, Node } from '@xyflow/react';
import { Button, Card, Input, message, Modal, notification, Radio, Select, Spin } from 'antd';
import Subtitle from '../../components/Subtitle';
import useSelectBorder from '../../store/useSceneData';
import CustomHandle from '../CustomHandle';
import { Loading3QuartersOutlined, SmileOutlined } from '@ant-design/icons';
import NodeOperation from '../../components/NodeOperation';
import { getDictionary, getOllamaModel } from '../../api/request';
import LexicalEdit, { LexicalEditRef } from '../../components/LexicalEdit';
import { lexicalEditParse } from '../../utils/utils';
import useInitVariable from '@/hooks/useInitVariable';

/**
 * 大模型节点
 * @param param0 
 * @returns 
 */

const creativity = `创意模式，生成的文本会有更大的随机性，模型会更加“冒险”地选择可能性较低的词语和句子。这通常导致生成内容更加多样化、创意丰富，但也可能出现不太相关或不合理的内容。`

const balance = `平衡模式：这是大多数情况下常用的温度设置，它在随机性和确定性之间达到了较好的平衡。生成的文本会有一定的创新性，但同时也保持了较好的连贯性和合理性。`

const accurate = `精确模式，模型的输出更倾向于选择概率较高的词语和句子，减少了随机性，输出内容通常更加确定、稳定和一致，减少创意，增加一致性：选择的词语更为保守，生成的内容更容易与训练数据中的常见模式保持一致。`

function TextUpdaterNode({ id, data }: Node) {
  const { setNodes, setCenter } = useReactFlow();
  const { select, setSelectId, debug, setDeBug } = useSelectBorder()
  const [modelSelect, setModelSelect] = useState<string[]>([])
  const [api, contextHolder] = notification.useNotification();
  const [llmParam, setLlmParam] = useState<string>(data.llmParam as string || 'balance')
  const [textParam, setTextParam] = useState<string>(data.promptAtom as string || '')
  const [tools, setTools] = useState<string>()
  const { initSetVariable } = useInitVariable()

  const options = [
    { label: '创意', value: 'creativity' },
    { label: '平衡', value: 'balance' },
    { label: '精确', value: 'accurate' },
  ];

  // 获取聚焦后的节点数据
  const handleFocus = () => {
    setSelectId(id);
    setDeBug(false)
  };

  const onChangeLlm = useCallback((value: string, type: string) => {
    setSelectedOption(value);
    setNodes((nodes) => {
      const node = nodes.find(node => node.id == id)
      if (type === "model") {
        node.data.model = value
      } else {
        node.data.modelUrl = value
      }
      return [...nodes];
    })
  }, []);

  const onChangePrompt = useCallback((value: string) => {
    setTextParam(value)
  }, []);

  const [isModalOpen, setIsModalOpen] = useState(false);

  // llm模型
  const [selectedOption, setSelectedOption] = useState(data.model || 'gpt-4o-mini');

  useEffect(() => {
    if (isModalOpen) {
      data.tools && setTools(JSON.stringify(data.tools))
      data.promptAtom && setTextParam(data.promptAtom as string)
    }
  }, [isModalOpen])

  const initMode = useCallback(async () => {
    // 设置变量
    initSetVariable(data.title as string || "LLM", id)

    // 初始化ollama
    const ollmaData = await getDictionary("MODEL")
    const ollama = await getOllamaModel() as any
    const ollamaSelect = ollama.models.map((value) => value.name)
    setModelSelect([...ollmaData.data.value.split(","), ...ollamaSelect])
  }, [])

  useEffect(() => {
    initMode()
  }, [])

  return (
    <NodeOperation nodeId={id} onClick={() => setIsModalOpen(true)}>
      <Card
        title={<div className='flex'>
          <Subtitle imgUrl='img/llm.png' title={data.title as string || 'LLM'} id={id}
            onBlur={(title) => initSetVariable(title, id)} />
          {select[id] && debug && <Spin indicator={<Loading3QuartersOutlined spin />} className='mt-[6px] ml-2' />}
        </div>}
        style={{
          outline: select[id] ? "2px solid #145FF0" : "none"
        }}
        className='w-[310px]'
        onClick={handleFocus}
        tabIndex={0}
      >
        <CustomHandle type="target" count={2} position={Position.Left} id="llmStart" style={{ top: 74 }} />
        <Modal
          title={<span>{data.title as string || 'LLM'}</span>}
          destroyOnClose={true}
          open={isModalOpen}
          footer={null}
          onCancel={() => {
            setNodes((nodes) => {
              const node = nodes.find(node => node.id == id)
              node.data.promptAtom = textParam
              node.data.prompt = lexicalEditParse(textParam)
              try {
                if (tools) {
                  node.data.tools = JSON.parse(tools)
                }
                return [...nodes];
              } catch (error) {
                message.error("json格式错误")
                return [...nodes];
              }
            })
            setIsModalOpen(false)
          }}>
          <Radio.Group
            block
            options={options}
            defaultValue="Apple"
            optionType="button"
            buttonStyle="solid"
            className='mb-2'
            value={llmParam}
            onChange={(e) => {
              setLlmParam(e.target.value)
              setNodes((nodes) => {
                const node = nodes.find(node => node.id == id)
                node.data.llmParam = e.target.value
                return [...nodes];
              })
              const param = e.target.value
              api.open({
                message: param == "creativity" ? '创意' : param == "balance" ? "平衡" : "精确",
                description:
                  param == "creativity" ? creativity : param == "balance" ? balance : accurate,
                icon: <SmileOutlined style={{ color: '#108ee9' }} />,
              });
            }}
          />
          <div className='mb-3'>
            <div className='font-bold text-[16px] mb-2'>函数注册</div>
            <Input.TextArea value={tools}
              onChange={(e) => setTools(e.target.value)}
              style={{ height: 30 }}
              className='bg-[#F3F4F7] text-[#485468]' />
          </div>
          <LexicalEdit onChange={onChangePrompt} value={textParam} title='上下文' />
          {contextHolder}
        </Modal>
        <div style={{ display: 'flex', flexDirection: "column" }}>
          <Select
            virtual={false}
            showSearch
            placeholder="请选择LLM模型"
            optionFilterProp="label"
            style={{ width: 254 }}
            onChange={value => onChangeLlm(value as string, "model")}
            value={selectedOption}
            className="nodrag"
            options={modelSelect.map((value) => {
              const document = <div className='flex'>
                <img src="img/openai.svg" className='h-[24px] mt-1' />
                <span className='ml-1'>{value}</span>
              </div>
              return { value, label: document }
            })}
          />
        </div>
        <CustomHandle count={1} type="source" position={Position.Right} id="llmEnd" style={{ top: 74 }} />
      </Card>
    </NodeOperation>
  );
}

export default memo(TextUpdaterNode)